package com.tuo51.observation.service.impl;

import com.tuo51.childcare.domain.feed.Feeds;
import com.tuo51.childcare.service.FeedsService;
import com.tuo51.childcare.service.WxPushService;
import com.tuo51.core.domain.staffs.Staff;
import com.tuo51.core.service.StaffService;
import com.tuo51.evaluate.domain.childrens.Children;
import com.tuo51.evaluate.repositories.children.ChildrenRepository;
import com.tuo51.evaluate.service.ChildrenService;
import com.tuo51.evaluate.service.UploadService;
import com.tuo51.foudation.constant.CommonConstant;
import com.tuo51.foudation.exception.BusinessException;
import com.tuo51.foudation.model.ErrorCode;
import com.tuo51.foudation.query.EvaluateQuery;
import com.tuo51.foudation.utils.DateUtil;
import com.tuo51.observation.domain.ObservatePoint;
import com.tuo51.observation.domain.ObservateRecord;
import com.tuo51.observation.repositories.ObservatePointRepository;
import com.tuo51.observation.repositories.ObservateRecordRepository;
import com.tuo51.observation.service.ObservationService;
import com.tuo51.observation.vo.observation.ObservationRecordChoiceVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.transaction.Transactional;
import java.util.*;
import java.util.stream.Collectors;


@Service
@Slf4j
public class ObservationServiceImpl implements ObservationService {

    @Autowired
    private ObservatePointRepository observatePointRepository;

    @Autowired
    private ObservateRecordRepository observateRecordRepository;

    @Autowired
    private ChildrenRepository childrenRepository;

    @Autowired
    private UploadService uploadService;

    @Autowired
    private ChildrenService childrenService;

    @Autowired
    private StaffService staffService;

    @Autowired
    private FeedsService feedsService;

    @Autowired
    private WxPushService wxPushService;


    private final static int MAX_POINTS_COUNT = 5;

    @Override
    public List<ObservatePoint> getObservatePointsByMonth(float month) {

        List<ObservatePoint> result = null;

        ObservatePoint less = observatePointRepository.findTop1ByMonthLessThanOrderByMonthDesc((int)month);
        ObservatePoint greate = observatePointRepository.findTop1ByMonthGreaterThanOrderByMonthAsc((int)month);

        if (less != null && greate != null){
            float l = month - less.getMonth();
            float g = greate.getMonth() - month;

            if (g > l){
                result = observatePointRepository.findByMonthOrderByIndexOnPaper(less.getMonth());
            }else{
                result = observatePointRepository.findByMonthOrderByIndexOnPaper(greate.getMonth());
            }
        }else if(less!= null){
            result = observatePointRepository.findByMonthOrderByIndexOnPaper(less.getMonth());
        }else if(greate != null){
            result = observatePointRepository.findByMonthOrderByIndexOnPaper(greate.getMonth());
        }

        //根据当天index来计算列表
        int size = result.size();
        Calendar c1 = Calendar.getInstance();
        c1.setTime(new Date());
        int days = c1.get(Calendar.DAY_OF_MONTH);

        int measure = days * MAX_POINTS_COUNT % size;

        int toIndex = (measure + 5);
        List<ObservatePoint> ret = result.subList(measure, (toIndex<=size?toIndex:size));
        if (ret.size() < MAX_POINTS_COUNT){
            ret.addAll(result);
            ret = ret.subList(0, MAX_POINTS_COUNT);
        }


        return ret;
    }

    @Override
    public List<ObservatePoint> getObservatePointsByChildrenId(String staffId, String childrenId){
        Children children = childrenService.getById(childrenId, staffId);
        if (children == null){
            throw new BusinessException(ErrorCode.CHILDREN_NOT_EXIST, "宝宝不存在");
        }
        float actualMonth = (float) DateUtil.betweenMonthsV2(new Date(), children.getBirthday());
        return getObservatePointsByMonth(actualMonth);
    }

    @Override
    public ObservateRecord getTodayFinishedRecords(String staffId, String childrenId){
        return observateRecordRepository.findTop1ByCurdate(childrenId);
    }

    @Override
    public ObservateRecord getRecordById(String recordId) {
        return observateRecordRepository.getOne(recordId);
    }

    @Override
    public Page<ObservateRecord> getRecords(String staffId, EvaluateQuery pagerQuery) {

        Children children = null;

        if (StringUtils.isNotBlank(pagerQuery.getChildrenId() )){
            children = childrenRepository.getByIdAndStaffId(pagerQuery.getChildrenId(), staffId);
        }
        if (children == null){
            throw new BusinessException(ErrorCode.CHILDREN_NOT_EXIST, "宝宝id为空");
        }

        return observateRecordRepository.findAll(new Specification<ObservateRecord>() {
            @Override
            public Predicate toPredicate(Root<ObservateRecord> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                Predicate base = cb.equal(root.get("childrenId"), pagerQuery.getChildrenId());

//        private String childrenId;
//        private String staffId;
//        private String childrenName;
//        private Integer month;
//        private Integer orderStatus;
//        private Integer status;
//        private String orderBy;
//        private String sequence;

                query.where(base);

                if (StringUtils.isNotEmpty(pagerQuery.getOrderBy())){
                    query.orderBy(cb.desc(root.get(pagerQuery.getOrderBy())));
                }else{
                    query.orderBy(cb.desc(root.get("created")));
                }

                return query.getRestriction();
            }
        }, PageRequest.of(pagerQuery.getPageNum(), pagerQuery.getPageSize()));
    }

    @Transactional
    @Override
    public Boolean addObservationRecord(Staff staff, String childrenId, List<Map> result ) {

        Children c = childrenService.getById(childrenId, staff.getId());
        if (c == null){
            throw new BusinessException(ErrorCode.CHILDREN_NOT_EXIST, "宝宝不存在" );
        }

        ObservateRecord record = new ObservateRecord();

        List<String> pointIds = result.stream().map(k->(String)k.get("pointId")).collect(Collectors.toList());
        List<ObservatePoint> points = observatePointRepository.findAllByIdIn(pointIds);
        Map<String, ObservatePoint> pointCache = points.stream().collect(Collectors.toMap(ObservatePoint::getId, a->a ));

        List<ObservationRecordChoiceVO> recordChoices = new ArrayList<>();
        record.setResult(recordChoices);

        record.setChildrenId(childrenId);
        record.setChildrenName(c.getName());
        record.setStaffId(staff.getId());
        record.setStaffName(staff.getRealName());

        for (Map map : result){
            String pointId = (String) map.get("pointId");
            ObservatePoint point = pointCache.get(pointId);
            if (point == null){
                continue;
            }

            String img = (String) map.get("img");

            Map option = (Map) map.get("option");
            String optionId = (String) option.get("optionId");
            String title = (String) option.get("title");
            Integer score = (Integer) option.get("score");

            ObservationRecordChoiceVO choiceVO = new ObservationRecordChoiceVO();

            choiceVO.setActivity(point.getActivity());
            choiceVO.setId(pointId);
            choiceVO.setAdvance(point.getAdvance());
            choiceVO.setDimensionId(point.getDimensionId());
            choiceVO.setDimensionName(point.getDimensionName());
            choiceVO.setObservation(point.getObservation());
            choiceVO.setOptionId(optionId);
            choiceVO.setOptionTitle(title);
            choiceVO.setOptionScore(score);
            choiceVO.setImg(img);
            choiceVO.setTitle(point.getTitle());
            choiceVO.setTools(point.getTools());

            recordChoices.add(choiceVO);
        }


        //保存 record
        observateRecordRepository.save(record);

        //feed 增加
        String title = String.format("%s 的一日观察记录", c.getName());
        String content = "宝贝最新一日观察记录新鲜出炉啦，老师都竖起了大拇指，继续加油！";

        //推送家长
        String guardianPhone = c.getExtendInfo().getGuardianPhone();
        if (StringUtils.isNotEmpty(guardianPhone)){
            List<Staff> parents = staffService.getByPhone(guardianPhone, null, CommonConstant.Platform.WXMP.codeOf());
            parents.stream().filter(o -> StringUtils.isNotEmpty(o.getOpenidMP())).forEach(k->{
                Feeds feed = feedsService.postFeeds(k, c, title, content, null, null, FeedsService.FeedsType.FeedDailyObserve, record.getId());
                wxPushService.pushObservationNewRecord(record, staff, k, c, feed.getId());
            });
        }

        return true;
    }


    @Override
    public String observationUpload(Integer mediaType, MultipartFile[] files) {
        String resourceUrl = "";
        if (Objects.nonNull(files) && files.length != 0) {
            resourceUrl += uploadService.uploadObservationRecordImg(mediaType, files);
        }

        return resourceUrl;
    }
}
